﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using LogX.Logging;
using MMessaging.MessagingEx.Logger;
using MMessaging.MessagingEx.Services;
using TUtils.BasicHelper;
using MMessaging.MessagingEx.Common;
using TUtils.BasicHelper.Logging;

namespace MMessaging.Address.Services
{
	/// <summary>
	/// Beispielimplementation einer Basisklasse für einen Service, der das Adress-Protokoll,
	/// wie es in MMessaging.Address.dll definiert ist.
	/// 
	/// MAddressServiceBase geht davon aus, dass alle Messages von MAddressMessageBase
	/// abgeleitet sind und "MAddressIsAlifeMessage" die Alife-Message des Adressprotokolls ist.
	/// </summary>
	public abstract class MAddressServiceBase :
		MServiceBaseDuplex<MAddressMessageBase>
	{
		public MAddress ServiceAddress
		{
			get;
			private set;
		}
		public IEnumerable<MAddress> ServiceRoles
		{
			get;
			private set;
		}

		private MServiceAddressPlugIn<MAddressMessageBase, MAddressIsAlifeMessage> _addressServicePlugin;
		private bool _started = false;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="serviceAddress"></param>
		/// <param name="intervallTimeAlifeMessage">
		/// Intervallzeit, für das zyklische Senden der Alife-Message
		/// </param>
		/// <param name="activateLoggingMessageProtocoll">
		/// true, wenn der Standard-Logger "LogXImplementor"
		/// für dieseb Service durch das Logging-Plug-in ""MLoggingPlugIn"
		/// ersetzt werden soll. Dieses sendet Logging-Messages statt direkt
		/// in eine Datei zu senden.</param>
		/// <param name="roles"></param>
		public MAddressServiceBase(
			MAddress serviceAddress,
			int intervallTimeAlifeMessage,
			params MAddress[] roles)
		{
			ServiceRoles = new List<MAddress>(roles);
			ServiceAddress = serviceAddress;
			_addressServicePlugin = new MServiceAddressPlugIn<MAddressMessageBase, MAddressIsAlifeMessage>(
					serviceAddress,
					roles,
					intervallTimeAlifeMessage,
					MAddressIsAlifeMessage.CreateIsAlifeMessage);
			RegisterPlugIn(
				_addressServicePlugin,
				PostMessage);

			AddMessageHandler(OnMessageReceived);
		}

		private void OnMessageReceived(IMTask<MAddressMessageBase> task)
		{
#			if DEBUG
			var debuggableMsg = task.CurrentMessage as IMDebugableMessage;
			if (debuggableMsg != null && debuggableMsg.Break)
			{
				// set a break point here ! ZVDZJHFESJ
				int a = 0;
			}
#			endif

			if (!_started)
			{
				if (task.CurrentMessage is MServiceStartedMessage)
				{
					_started = true;
					OnServiceStarted(task);
				}
			}

		}

		protected virtual void OnServiceStarted(IMTask<MAddressMessageBase> task)
		{
			RemoveMessageHandler(OnMessageReceived);
		}

		public override void PostMessage(MAddressMessageBase message)
		{
			TLog.Instance.LogWithAdditionalValues(
				errorLevel: LogSeverityEnum.INFO,
				loggingInstance: this,
				withStackTrace: false,
				formattedText: "sending message",
				parameters: null,
				additionalLogValues: new ILogValue[]
					{
						new LogValue(
							MPredefinedLoggingValueIDs.SendingMessageID,
							()=>message.GetHashCode().ToString(CultureInfo.InvariantCulture)),
						new LogValue(
							MPredefinedLoggingValueIDs.SendingMessageContent,
							()=>message.ToString())
					});

			if (message.Receiver.Equals(this.ServiceAddress))
			{
				LoopbackQueue.PostMessage(message);
			}
			else
			{
				Channel.PostMessage(message);
				if (ServiceRoles.Any(role => role.Equals(message.Receiver)))
					LoopbackQueue.PostMessage(message);
			}
		}

		public override void StartAsync()
		{
			base.StartAsync();

			LoopbackQueue.PostMessage(new MServiceStartedMessage(
				ServiceAddress,
				ServiceAddress,
				DateTime.UtcNow));
		}

		public void BeginInvoke(Action action)
		{
			BeginInvoke<MDispatcherMessage>(action);
		}
	}
}
